//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using Microsoft.Research.ScientificWorkflow.TridentComposer;
using Microsoft.Research.ScientificWorkflow.TridentModel;
using Microsoft.Research.ScientificWorkflow.TridentUtilities;
using Er = Microsoft.Research.DataLayer;
using TridentAPI;

namespace Microsoft.Research.ScientificWorkflow.UIDesigner
{
    /// <summary>
    /// Selects the appropriate template to be applied.
    /// </summary>
    public class PropertyValueTemplateSelectorForList : DataTemplateSelector
    {
        /// <summary>
        /// Gets the template based on some conditions.
        /// </summary>
        /// <param name="item">
        /// The item for which the template is to be applied.
        /// </param>
        /// <param name="container">
        /// Container.
        /// </param>
        /// <returns>
        /// Appropriate template.
        /// </returns>
        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            string templateKey = "parameterLayout";
            ParameterDescriptionModel currentParam = item as ParameterDescriptionModel;
            bool isCustomType = false;

            if (currentParam != null)
            {
                if (!currentParam.IsDatabound && (currentParam.DataType.Equals("System.Boolean") || currentParam.DataType.Equals("System.Enum")))
                {
                    templateKey = "ComboboxTemplate";
                }
                else if (currentParam.IsDatabound)
                {
                    templateKey = "NonEditableValueTemplate";
                }
                else
                {
                    try
                    {
                        Er.TypeInitializer typeInit = TypeProviderHelper.FetchTypeInitializer(currentParam.DataType, Er.Runtime.WPF);
                        isCustomType = typeInit != null;
                    }
                    catch (Exception)
                    {
                    }
                    templateKey = isCustomType ? "CustomDatatypeTemplate" : "EditableValueTemplate";
                }
            }
            else
            {
                return null;
            }
            return (DataTemplate)((FrameworkElement)container).FindResource(templateKey);
        }
    }

    /// <summary>
    /// Converts various values based on the parameters.
    /// </summary>
    public class InputControlConverter : IMultiValueConverter
    {
        #region IMultiValueConverter Members

        /// <summary>
        /// Convert based on value and parameter.
        /// </summary>
        /// <param name="values">
        /// The current values.
        /// </param>
        /// <param name="targetType">
        /// The expected type.
        /// </param>
        /// <param name="parameter">
        /// Passed parameter.
        /// </param>
        /// <param name="culture">
        /// Culture.
        /// </param>
        /// <returns>
        /// Modified value.
        /// </returns>
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            object retVal = null;
            if (parameter != null && values != null && values.Length > 0)
            {
                ParameterDescriptionModel paramModel = values[0] as ParameterDescriptionModel;
                DatabindModel dataBindModel = null;
                if (paramModel != null)
                {
                    switch (parameter.ToString())
                    {
                        case "CustomTypeTextBox":
                            try
                            {
                                Er.TypeInitializer typeInit = TypeProviderHelper.FetchTypeInitializer(paramModel.DataType, Er.Runtime.WPF);
                                if (typeInit != null)
                                {
                                    string deserializedVal = (paramModel.Value != null) ? paramModel.Value.ToString() : string.Empty;
                                    BaseTypeInitializer baseTypeinit = ActivityComposer.LoadInitializer(typeInit, deserializedVal);
                                    if (baseTypeinit != null)
                                    {
                                        retVal = baseTypeinit.GetStringValue();
                                    }
                                }
                            }
                            catch (Exception)
                            {
                            }

                            break;

                        case "ReadOnlyBoundTextBox":
                            if (values.Length > 1)
                            {
                                dataBindModel = values[1] as DatabindModel;
                                if (dataBindModel != null)
                                {
                                    StringBuilder sBuilder = new StringBuilder();
                                    sBuilder.Append(dataBindModel.SourceActivityName);
                                    sBuilder.Append(".");
                                    sBuilder.Append(dataBindModel.SourcePropertyName);
                                    retVal = sBuilder.ToString();
                                }
                            }

                            break;

                        case "ReadOnlyBoundTextBoxTooltip":
                            if (values.Length > 1)
                            {
                                dataBindModel = values[1] as DatabindModel;
                                if (dataBindModel != null)
                                {
                                    StringBuilder sBuilder = new StringBuilder();
                                    sBuilder.Append("Source activity: ");
                                    sBuilder.Append(dataBindModel.SourceActivityName);
                                    sBuilder.Append(Environment.NewLine);
                                    sBuilder.Append("Source property: ");
                                    sBuilder.Append(dataBindModel.SourcePropertyName);
                                    retVal = sBuilder.ToString();
                                }
                            }

                            break;

                        case "comboBoxCtrl":
                            List<TridentPropertyBindingObject> valuesList = new List<TridentPropertyBindingObject>();
                            if (paramModel.DataType.Equals("System.Boolean"))
                            {
                                TridentPropertyBindingObject trueObj = new TridentPropertyBindingObject(true, "True", paramModel);
                                TridentPropertyBindingObject falseObj = new TridentPropertyBindingObject(false, "False", paramModel);
                                valuesList.Add(trueObj);
                                valuesList.Add(falseObj);
                            }

                            retVal = valuesList;
                            break;
                    }
                }
            }

            return retVal;
        }

        /// <summary>
        /// Convert back based on value and parameter.
        /// </summary>
        /// <param name="value">
        /// The current value.
        /// </param>
        /// <param name="targetTypes">
        /// The expected types.
        /// </param>
        /// <param name="parameter">
        /// Passed parameter.
        /// </param>
        /// <param name="culture">
        /// Culture.
        /// </param>
        /// <returns>
        /// Old values.
        /// </returns>
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            return new object[] { value };
        }

        #endregion
    }

    /// <summary>
    /// 
    /// </summary>
    public class OppositeVisibilityConverter : IValueConverter
    {
        /// <summary>
        /// Convert based on value and parameter.
        /// </summary>
        /// <param name="value">
        /// The current value.
        /// </param>
        /// <param name="targetType">
        /// The expected type.
        /// </param>
        /// <param name="parameter">
        /// Passed parameter.
        /// </param>
        /// <param name="culture">
        /// Culture.
        /// </param>
        /// <returns>
        /// Modified value.
        /// </returns>
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            Visibility result = Visibility.Visible;
            if ((bool)value)
            {
                result = Visibility.Collapsed;
            }
            return result;
        }

        /// <summary>
        /// Convert back based on value and parameter.
        /// </summary>
        /// <param name="value">
        /// The current value.
        /// </param>
        /// <param name="targetType">
        /// The expected type.
        /// </param>
        /// <param name="parameter">
        /// Passed parameter.
        /// </param>
        /// <param name="culture">
        /// Culture.
        /// </param>
        /// <returns>
        /// Old value.
        /// </returns>
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return value;
        }
    }

    /// <summary>
    /// Creates an appropriate tooltip.
    /// </summary>
    public class PropertyListNameTooltipGenerator : IValueConverter
    {
        /// <summary>
        /// Convert based on value and parameter.
        /// </summary>
        /// <param name="value">
        /// The current value.
        /// </param>
        /// <param name="targetType">
        /// The expected type.
        /// </param>
        /// <param name="parameter">
        /// Passed parameter.
        /// </param>
        /// <param name="culture">
        /// Culture.
        /// </param>
        /// <returns>
        /// Modified value.
        /// </returns>
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            ParameterDescriptionModel paramModel = value as ParameterDescriptionModel;
            if (paramModel != null)
            {
                return PropertyListNameTooltipGenerator.CreateParamTooltip(paramModel);
            }

            return value;
        }

        /// <summary>
        /// Convert back based on value and parameter.
        /// </summary>
        /// <param name="value">
        /// The current value.
        /// </param>
        /// <param name="targetType">
        /// The expected type.
        /// </param>
        /// <param name="parameter">
        /// Passed parameter.
        /// </param>
        /// <param name="culture">
        /// Culture.
        /// </param>
        /// <returns>
        /// Old value.
        /// </returns>
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return value;
        }

        /// <summary>
        /// Creates Tooltip for Parameter
        /// </summary>
        private static StackPanel CreateParamTooltip(ParameterDescriptionModel paramModel)
        {
            StackPanel topPanel = new StackPanel();
            topPanel.MaxWidth = 170;
            TextBlock activityName = new TextBlock();
            TextBlock propertyName = new TextBlock();
            
            string activity = paramModel.PropertyPaneDisplayName.Substring(0, paramModel.PropertyPaneDisplayName.IndexOf('.'));
            activityName.Text = TridentResourceManager.GetString("PropertyPaneTooltipActivity") + activity;
            propertyName.Text = TridentResourceManager.GetString("PropertyPaneTooltipProperty") + paramModel.PropertyName;

            topPanel.Children.Add(activityName);
            topPanel.Children.Add(propertyName);

            if (null != paramModel.DataType)
            {
                TextBlock dataType = new TextBlock();
                dataType.Text = TridentResourceManager.GetString("PropertyPaneTooltipDatatype") + paramModel.DataType.ToString();
                topPanel.Children.Add(dataType);
            }

            if (null != paramModel.Description)
            {
                TextBlock description = new TextBlock();
                description.TextWrapping = TextWrapping.Wrap;
                description.Text = TridentResourceManager.GetString("PropertyPaneTooltipDesc") + paramModel.Description;
                topPanel.Children.Add(description);

            }
            return topPanel;
        }
    }

    public class ErrorTooltipGenerator : IValueConverter
    {
        #region IValueConverter Members

        /// <summary>
        /// Convert based on value and parameter.
        /// </summary>
        /// <param name="value">
        /// The current value.
        /// </param>
        /// <param name="targetType">
        /// The expected type.
        /// </param>
        /// <param name="parameter">
        /// Passed parameter.
        /// </param>
        /// <param name="culture">
        /// Culture.
        /// </param>
        /// <returns>
        /// Modified value.
        /// </returns>
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            ParameterDescriptionModel parameterModel = value as ParameterDescriptionModel;
            return TridentResourceManager.GetString("InvalidPropertyPaneInput", parameterModel.DataType);
        }

        /// <summary>
        /// Convert back based on value and parameter.
        /// </summary>
        /// <param name="value">
        /// The current value.
        /// </param>
        /// <param name="targetType">
        /// The expected type.
        /// </param>
        /// <param name="parameter">
        /// Passed parameter.
        /// </param>
        /// <param name="culture">
        /// Culture.
        /// </param>
        /// <returns>
        /// Old value.
        /// </returns>
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return value;
        }

        #endregion
    }
}
